package com.wan.core.timer.bucket;

import cn.hutool.log.StaticLog;
import com.wan.core.timer.ProtectHelper;
import com.wan.core.timer.TimerWheel;
import com.wan.core.timer.task.TaskLinked;
import com.wan.core.timer.task.TaskNode;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;

/**
 * 槽位
 * @author wwh
 * @date 2022/6/28 11:45
 */
public class Bucket extends ProtectHelper {

    private final TimerWheel timerWheel;
    private final int index;
    private final TaskLinked head; //链表头部
    private TaskLinked tail; //链表尾部

    public Bucket(int index,TimerWheel timerWheel) {
        this.index = index;
        this.timerWheel = timerWheel;
        head = new TaskLinked(null,this);
        tail = head;
    }

    public TimerWheel getTimerWheel() {
        return timerWheel;
    }

    /**
     * 时间点触发，对槽内任务触发降级检测
     */
    public void trigger(){
        foreach(task -> {
            //先检测round，大于0减一，降到0再降级
            long round = task.taskNode.getRound();
            if(round > 0){
                task.taskNode.setRound(round - 1);
            }else{
                timerWheel.degrade(task.taskNode);
            }
        });
    }

    /**
     * 删除任务
     * tip：为了实现无锁操作，不在调度线程中，则会加入队列中等待调度线程执行
     */
    public void remove(TaskNode taskNode){
        Boolean sync = timerWheel.findMinWheel().threadLocal.get();
        if(sync == null || !sync){
            addTickRunnable(timerWheel,()->remove(taskNode));
            return;
        }
        foreach((t)->{
            if(t.taskNode.equals(taskNode)){
                if(t == tail){
                    tail = tail.prev;
                }
                t.removeSelf();
                //StaticLog.info("任务出槽->{}",taskNode);
            }
        });
    }

    /**
     * 添加任务
     * tip：不在调度线程中，则会加入队列中等待调度线程执行
     */
    public void add(TaskNode taskNode){
        Boolean sync = timerWheel.findMinWheel().threadLocal.get();
        if(sync == null || !sync){
            addTickRunnable(timerWheel,()->add(taskNode));
            return;
        }
        TaskLinked taskLinked = new TaskLinked(taskNode,this);
        //新任务放到尾部
        tail.postInsert(taskLinked);
        tail = taskLinked;
        //StaticLog.info("任务进槽->{}",taskNode);
    }

    public void foreach(Consumer<TaskLinked> consumer){
        TaskLinked linked = head.next;
        while (linked != null){
            consumer.accept(linked);
            linked = linked.next;
        }
    }

    public int getNodeCount(){
        AtomicInteger num = new AtomicInteger();
        foreach(taskLinked -> num.incrementAndGet());
        return num.get();
    }

    @Override
    public String toString() {
        return "Bucket[index=" + index +
                ",nodeCount=" + getNodeCount() +
                ",timerWheelType=" + timerWheel.getRoundWheel() + "]";
    }
}
